package com.study.nacos.nacosstudy.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Description :
 * @Version : V1.0.0
 * @Date : 2022/8/1 19:32
 */
@RestController
public class SentinelTest {

    @GetMapping("/clean/{id}")
    public String clean(@PathVariable("id") int id) {
        return "Hello clean " + id;
    }

    @SentinelResource(value = "hello", blockHandler = "blockHandlerHello")
    @GetMapping("/say")
    public String hello() {
        return "hello, Mic";
    }

    public String blockHandlerHello(BlockException e) {
        return "被限流了";
    }

    @GetMapping("/dash")
    public String dash() {
        return "Hello Dash";
    }


    @GetMapping("/test")
    @SentinelResource(value = "order/test", entryType = EntryType.OUT, blockHandler = "exceptionHandler", fallback = "helloFallback")
    public String test() {
        double random = Math.random();
        System.out.println(random);
        System.out.println(1 / 0);
        return "success";
    }

    @GetMapping("/add")
    public String add() {
        System.out.println("下单成功");
        System.out.println(1 / 0);
        return "Hello World ";
    }

    @GetMapping("/flow")
    public String flow() throws FlowException {
        throw new FlowException("flow");
    }

    public String flowBlockHandler(BlockException e) {
        return "被流控了";
    }

    @GetMapping("/flowThread")
    @SentinelResource(value = "flowThread", blockHandler = "flowBlockHandler")
    public String flowThread() throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
        return "正常访问";
    }

    public String exceptionHandler(BlockException ex) {
        System.out.println("exception");
        return "exception";
    }

    public String helloFallback() {
        return "hello fall back";
    }


    private static void doSomething(String resource) {
        try (Entry entry = SphU.entry(resource)) {
            // 业务逻辑处理
            System.out.println(resource + " " + System.currentTimeMillis());
        } catch (BlockException e) {
            // 处理流控的逻辑
            System.out.println(resource + " block exception, trigger traffic limit");
        }
    }

    private static void reloadFlowRules(String resource) {
        FlowRule rule = new FlowRule();
        rule.setResource(resource);
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(1);
        List<FlowRule> rules = FlowRuleManager.getRules();
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

    public static void main(String[] args) {
        ArrayList<String> resources = new ArrayList<>();
        resources.add("https://192.168.121.18:8080/test/1");
        resources.add("https://192.168.121.18:8080/test/2");
        resources.add("https://192.168.121.18:8080/test/3");
        resources.add("https://192.168.121.18:8080/test/4");
        resources.add("https://192.168.11.18:8080/test/5");
        resources.add("https://192.168.131.18:8080/test/6");
        HashSet<String> strings = new HashSet<>();
        for (int i = 0; i < 3; i++) {
            resources.forEach(resourceName -> {
                if (!strings.contains(resourceName)) {
                    strings.add(resourceName);
                    reloadFlowRules(resourceName );
                }
                doSomething(resourceName);
            });
        }
    }

}
